package org.example.datasource.pooled;

import lombok.Data;
import org.apache.ibatis.reflection.invoker.Invoker;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Author: luyg
 * @Date: 2024/11/13/0:50
 * @Description:
 */
@Data
public class PooledConnection implements InvocationHandler {

    private static final String CLOSE = "close";
    private static final Class<?>[] IFACES=new Class<?>[]{Connection.class};

    private int hashCode=0;
    //数据库的连接信息
    private PooledDataSource dataSource;
    //真实连接
    private Connection realConnection;
    //代理连接
    private Connection proxyConnection;
    //记录时间来看看是否使用超时
    private long checkoutTimestamp;
    //创建时间
    private long createdTimestamp;
    //最近一次使用时间
    private long lastUsedTimestamp;
    //数据库地址+用户名+密码的hashCode
    private int connectionTypeCode;
    //连接是否是正常
    private boolean valid;

    public PooledConnection(Connection connection, PooledDataSource dataSource) {
        this.hashCode = connection.hashCode();
        this.dataSource = dataSource;
        this.realConnection = connection;
        this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(),IFACES,this);
        this.createdTimestamp = System.currentTimeMillis();
        this.lastUsedTimestamp = System.currentTimeMillis();
        this.valid = true;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if(CLOSE.hashCode()==methodName.hashCode()&&CLOSE.equals(methodName)){
            dataSource.pushConnection(this);
            return null;
        }else {
            if(!Object.class.equals(method.getDeclaringClass())){
                checkConnection();
            }
            return method.invoke(realConnection,args);
        }
    }

    private void checkConnection() throws SQLException {
        if(!valid){
            throw new SQLException("Error accessing PooledConnection. Connection is invalid.");
        }
    }
    public void invalidate() {
        valid = false;
    }
    public boolean isValid() {
        return valid && realConnection != null && dataSource.pingConnection(this);
    }
    public int getRealHashCode() {
        return realConnection == null ? 0 : realConnection.hashCode();
    }
    public long getTimeElapsedSinceLastUse() {
        return System.currentTimeMillis() - lastUsedTimestamp;
    }
    @Override
    public int hashCode() {
        return hashCode;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof PooledConnection) {
            return realConnection.hashCode() == (((PooledConnection) obj).realConnection.hashCode());
        } else if (obj instanceof Connection) {
            return hashCode == obj.hashCode();
        } else {
            return false;
        }
    }

}
